const express = require('express');
const cors = require('cors');
const fs = require('fs-extra');
const path = require('path');
const { promisify } = require('util');
const toml = require('toml');

const app = express();
app.use(cors());
app.use(express.json());

// 根目录路径
const ROOT_DIR = path.join(__dirname, '..');

// 读取配置文件
const configPath = path.join(ROOT_DIR, 'config.toml');
const configContent = fs.readFileSync(configPath, 'utf-8');
const config = toml.parse(configContent);

// 路径配置
const PATHS = {
    VIDEOS_DIR: path.join(ROOT_DIR, config.server.videos_directory),      // 视频目录
    HTML_DIR: path.join(ROOT_DIR, 'html'),          // HTML 目录
    JS_DIR: __dirname,                              // JS 目录（当前目录）
    INDEX_FILE: path.join(ROOT_DIR, path.basename(config.server.index_file_path)) // 索引文件路径
};

// 静态文件服务
app.use(express.static(PATHS.HTML_DIR));

// 添加视频请求日志和文件检查，支持HTTP Range请求和缓存优化
app.use('/videos', async (req, res, next) => {
    const clientIP = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.socket.remoteAddress || (req.connection.socket ? req.connection.socket.remoteAddress : null);
    const userAgent = req.headers['user-agent'] || 'Unknown';
    const referer = req.headers['referer'] || 'Direct';
    
    console.log(`${new Date().toISOString()} 视频请求: ${req.method} ${req.url} | IP: ${clientIP} | UA: ${userAgent.substring(0, 50)}${userAgent.length > 50 ? '...' : ''} | 来源: ${referer}`);

    // 检查文件是否存在
    const filePath = path.join(PATHS.VIDEOS_DIR, decodeURIComponent(req.url));
    try {
        const exists = await fs.pathExists(filePath);
        console.log(`${new Date().toISOString()} 文件存在检查: ${filePath} ${exists ? '存在' : '不存在'} | 请求来自: ${clientIP}`);
        if (!exists) {
            console.log(`${new Date().toISOString()} 文件不存在: ${filePath} | 请求来自: ${clientIP}`);
            return res.status(404).send('文件不存在');
        }
    } catch (error) {
        console.log(`${new Date().toISOString()} 文件检查出错: ${filePath} ${error.message} | 请求来自: ${clientIP}`);
        return res.status(500).send('服务器内部错误');
    }

    // 获取文件信息
    let stat;
    try {
        stat = await fs.stat(filePath);
    } catch (error) {
        console.log(`${new Date().toISOString()} 获取文件信息失败: ${filePath} ${error.message}`);
        return res.status(500).send('服务器内部错误');
    }

    const fileSize = stat.size;
    const range = req.headers.range;
    
    // 设置缓存控制头，视频文件缓存1小时
    res.setHeader('Cache-Control', 'public, max-age=3600');
    res.setHeader('ETag', `"${stat.mtime.getTime()}_${stat.size}"`);
    
    // 检查If-None-Match头，实现ETag验证
    if (req.headers['if-none-match'] === `"${stat.mtime.getTime()}_${stat.size}"`) {
        return res.status(304).send(); // 文件未修改，返回304
    }

    // 添加视频流支持的响应头
    res.setHeader('Accept-Ranges', 'bytes');
    res.setHeader('Content-Type', 'video/mp4');
    
    // 添加CORS头以支持跨域请求
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Headers', 'Range, Accept-Ranges');

    // 如果有Range请求头，处理断点续传
    if (range) {
        // 解析Range头部，格式为 "bytes=0-1023"
        const parts = range.replace(/bytes=/, "").split("-");
        const start = parseInt(parts[0], 10);
        const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;

        // 验证范围的有效性
        if (start >= fileSize || end >= fileSize) {
            // 如果请求的范围超出文件大小，返回416状态码
            res.status(416).setHeader('Content-Range', `bytes */${fileSize}`);
            console.log(`${new Date().toISOString()} 视频范围请求无效: ${range} | 文件大小: ${fileSize} | 请求来自: ${clientIP}`);
            return res.send();
        }

        // 计算响应内容的大小
        const chunksize = (end - start) + 1;
        
        // 设置206 Partial Content状态码和相关头部
        res.status(206);
        res.setHeader('Content-Range', `bytes ${start}-${end}/${fileSize}`);
        res.setHeader('Content-Length', chunksize);

        // 创建可读流并传输指定范围的数据
        const fileStream = fs.createReadStream(filePath, { start, end });
        
        // 记录传输开始
        console.log(`${new Date().toISOString()} 开始发送视频片段: ${start}-${end}/${fileSize} (${chunksize} bytes) | 请求来自: ${clientIP}`);
        
        // 监听流事件以更好地处理错误
        fileStream.on('error', (err) => {
            console.error(`${new Date().toISOString()} 视频流传输错误: ${err.message} | 文件: ${filePath} | 请求来自: ${clientIP}`);
            if (!res.headersSent) {
                res.status(500).send('视频流传输错误');
            }
        });
        
        // 监听传输完成
        fileStream.on('end', () => {
            console.log(`${new Date().toISOString()} 视频片段传输完成: ${start}-${end}/${fileSize} | 请求来自: ${clientIP}`);
        });
        
        fileStream.pipe(res);
    } else {
        // 没有Range请求头，发送整个文件
        res.setHeader('Content-Length', fileSize);
        const fileStream = fs.createReadStream(filePath);
        
        console.log(`${new Date().toISOString()} 开始发送完整视频: ${fileSize} bytes | 文件: ${path.basename(filePath)} | 请求来自: ${clientIP}`);
        
        // 监听流事件以更好地处理错误
        fileStream.on('error', (err) => {
            console.error(`${new Date().toISOString()} 视频流传输错误: ${err.message} | 文件: ${filePath} | 请求来自: ${clientIP}`);
            if (!res.headersSent) {
                res.status(500).send('视频流传输错误');
            }
        });
        
        // 监听传输完成
        fileStream.on('end', () => {
            console.log(`${new Date().toISOString()} 完整视频传输完成: ${fileSize} bytes | 文件: ${path.basename(filePath)} | 请求来自: ${clientIP}`);
        });
        
        fileStream.pipe(res);
    }
});
app.use('/css', express.static(path.join(ROOT_DIR, 'css')));
app.use('/js', express.static(path.join(ROOT_DIR, 'js')));
app.use(express.static(path.join(ROOT_DIR, 'html')));

// 配置 - 使用TOML配置文件中的设置
const serverConfig = {
    videosDirectory: PATHS.VIDEOS_DIR,
    indexFilePath: PATHS.INDEX_FILE,
    supportedExtensions: config.server.supported_extensions,
    maxIndexAge: config.server.max_index_age
};

// 确保视频目录存在
fs.ensureDirSync(serverConfig.videosDirectory);

/**
 * 生成视频索引
 */
async function generateVideoIndex() {
    const startTime = Date.now();
    console.log(`${new Date().toISOString()} 开始生成视频索引...`);
    
    try {
        const files = await fs.readdir(serverConfig.videosDirectory);
        console.log(`${new Date().toISOString()} 扫描到 ${files.length} 个文件/目录`);
        
        const videos = [];
        let skippedFiles = 0;
        let processedFiles = 0;

        for (const file of files) {
            const ext = path.extname(file).toLowerCase();
            if (serverConfig.supportedExtensions.includes(ext)) {
                const fullPath = path.join(serverConfig.videosDirectory, file);
                try {
                    const stats = await fs.stat(fullPath);

                    // 只处理文件，跳过目录
                    if (stats.isFile()) {
                        videos.push({
                            id: Date.now() + Math.random(),
                            title: path.basename(file, ext),
                            description: `本地视频文件: ${file}`,
                            url: `/videos/${encodeURIComponent(file)}`,
                            filename: file,
                            size: stats.size,
                            duration: 0, // 将在前端获取
                            createdAt: stats.birthtime,
                            updatedAt: stats.mtime
                        });
                        processedFiles++;
                    }
                } catch (fileError) {
                    console.warn(`${new Date().toISOString()} 处理文件时出错 ${fullPath}: ${fileError.message}`);
                    skippedFiles++;
                }
            } else {
                skippedFiles++;
            }
        }

        const indexData = {
            videos,
            generatedAt: new Date(),
            total: videos.length,
            stats: {
                scannedFiles: files.length,
                processedFiles: processedFiles,
                skippedFiles: skippedFiles,
                processingTime: Date.now() - startTime
            }
        };

        await fs.writeJson(serverConfig.indexFilePath, indexData, { spaces: 2 });
        console.log(`${new Date().toISOString()} 生成视频索引完成，共找到 ${videos.length} 个视频 (处理时间: ${Date.now() - startTime}ms)`);
        console.log(`${new Date().toISOString()} 统计信息 - 扫描: ${files.length}, 处理: ${processedFiles}, 跳过: ${skippedFiles}`);
        return indexData;
    } catch (error) {
        console.error(`${new Date().toISOString()} 生成索引失败:`, error);
        console.error(`${new Date().toISOString()} 错误堆栈:`, error.stack);
        throw error;
    }
}

/**
 * 获取视频索引
 */
async function getVideoIndex(forceUpdate = false) {
    console.log(`${new Date().toISOString()} 开始获取视频索引 | 强制更新: ${forceUpdate}`);
    
    try {
        // 检查索引文件是否存在且未过期
        if (!forceUpdate && await fs.pathExists(serverConfig.indexFilePath)) {
            const indexData = await fs.readJson(serverConfig.indexFilePath);
            const indexAge = Date.now() - new Date(indexData.generatedAt).getTime();
            const indexAgeMinutes = Math.floor(indexAge / 1000 / 60);

            if (indexAge < serverConfig.maxIndexAge) {
                console.log(`${new Date().toISOString()} 使用缓存的视频索引 | 缓存时间: ${indexAgeMinutes}分钟 | 视频数量: ${indexData.total}`);
                return indexData;
            }
            console.log(`${new Date().toISOString()} 索引已过期 (${indexAgeMinutes}分钟 > ${(serverConfig.maxIndexAge / 1000 / 60).toFixed(1)}分钟)，重新生成`);
        } else if (forceUpdate) {
            console.log(`${new Date().toISOString()} 强制更新索引`);
        } else {
            console.log(`${new Date().toISOString()} 索引文件不存在，生成新索引`);
        }

        // 生成新索引
        return generateVideoIndex();
    } catch (error) {
        console.error(`${new Date().toISOString()} 获取索引失败:`, error.message);
        console.error(`${new Date().toISOString()} 错误堆栈:`, error.stack);
        // 如果获取失败，强制重新生成
        console.log(`${new Date().toISOString()} 尝试重新生成索引...`);
        return generateVideoIndex();
    }
}

// API接口
app.get('/api/videos', async (req, res) => {
    const startTime = Date.now();
    const clientIP = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
    
    console.log(`${new Date().toISOString()} API请求: GET /api/videos | IP: ${clientIP}`);
    
    try {
        const indexData = await getVideoIndex();
        const responseTime = Date.now() - startTime;
        console.log(`${new Date().toISOString()} API响应: GET /api/videos | 状态: 200 | 耗时: ${responseTime}ms | 返回: ${indexData.videos.length} 个视频`);
        res.json(indexData.videos);
    } catch (error) {
        const responseTime = Date.now() - startTime;
        console.error(`${new Date().toISOString()} API错误: GET /api/videos | 状态: 500 | 耗时: ${responseTime}ms | 错误: ${error.message}`);
        res.status(500).json({ error: '获取视频列表失败' });
    }
});

app.post('/api/update-index', async (req, res) => {
    const startTime = Date.now();
    const clientIP = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
    
    console.log(`${new Date().toISOString()} API请求: POST /api/update-index | IP: ${clientIP}`);
    
    try {
        const indexData = await getVideoIndex(true);
        const responseTime = Date.now() - startTime;
        console.log(`${new Date().toISOString()} API响应: POST /api/update-index | 状态: 200 | 耗时: ${responseTime}ms | 更新: ${indexData.total} 个视频`);
        res.json({
            success: true,
            message: `索引更新成功，共找到 ${indexData.total} 个视频`,
            total: indexData.total,
            processingTime: indexData.stats ? indexData.stats.processingTime : 'N/A'
        });
    } catch (error) {
        const responseTime = Date.now() - startTime;
        console.error(`${new Date().toISOString()} API错误: POST /api/update-index | 状态: 500 | 耗时: ${responseTime}ms | 错误: ${error.message}`);
        res.status(500).json({ error: '更新索引失败' });
    }
});

app.post('/api/video-played', async (req, res) => {
    const startTime = Date.now();
    const clientIP = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
    const { videoId, duration } = req.body;
    
    console.log(`${new Date().toISOString()} API请求: POST /api/video-played | IP: ${clientIP} | 视频ID: ${videoId} | 时长: ${duration}`);
    
    try {
        // 这里可以记录视频播放状态
        console.log(`${new Date().toISOString()} 视频 ${videoId} 播放完成，时长: ${duration}`);
        const responseTime = Date.now() - startTime;
        console.log(`${new Date().toISOString()} API响应: POST /api/video-played | 状态: 200 | 耗时: ${responseTime}ms`);
        res.json({ success: true });
    } catch (error) {
        const responseTime = Date.now() - startTime;
        console.error(`${new Date().toISOString()} API错误: POST /api/video-played | 状态: 500 | 耗时: ${responseTime}ms | 错误: ${error.message}`);
        res.status(500).json({ error: '记录播放状态失败' });
    }
});

app.get('/api/status', (req, res) => {
    const startTime = Date.now();
    const clientIP = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
    
    console.log(`${new Date().toISOString()} API请求: GET /api/status | IP: ${clientIP}`);
    
    const statusData = {
        status: 'running',
        timestamp: new Date(),
        version: '1.0.0',
        videosDirectory: serverConfig.videosDirectory,
        supportedExtensions: serverConfig.supportedExtensions,
        uptime: process.uptime()
    };
    
    const responseTime = Date.now() - startTime;
    console.log(`${new Date().toISOString()} API响应: GET /api/status | 状态: 200 | 耗时: ${responseTime}ms`);
    res.json(statusData);
});

app.get('/api/config', (req, res) => {
    const startTime = Date.now();
    const clientIP = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
    
    console.log(`${new Date().toISOString()} API请求: GET /api/config | IP: ${clientIP}`);
    
    const configData = {
        server: {
            port: config.server.port,
            videos_directory: config.server.videos_directory,
            index_file_path: config.server.index_file_path,
            supported_extensions: config.server.supported_extensions,
            max_index_age: config.server.max_index_age
        },
        player: {
            min_switch_interval: config.player.min_switch_interval,
            swipe_threshold: config.player.swipe_threshold,
            swipe_time_threshold: config.player.swipe_time_threshold,
            roll_delay: config.player.roll_delay,
            seek_step: config.player.seek_step,
            max_seek_step: config.player.max_seek_step,
            seek_acceleration_threshold: config.player.seek_acceleration_threshold
        }
    };
    
    const responseTime = Date.now() - startTime;
    console.log(`${new Date().toISOString()} API响应: GET /api/config | 状态: 200 | 耗时: ${responseTime}ms`);
    res.json(configData);
});

// 错误处理中间件
app.use((err, req, res, next) => {
    const clientIP = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
    const userAgent = req.headers['user-agent'] || 'Unknown';
    
    console.error(`${new Date().toISOString()} 服务器内部错误:`);
    console.error(`  请求URL: ${req.method} ${req.url}`);
    console.error(`  客户端IP: ${clientIP}`);
    console.error(`  User-Agent: ${userAgent.substring(0, 50)}${userAgent.length > 50 ? '...' : ''}`);
    console.error(`  错误消息: ${err.message}`);
    console.error(`  错误堆栈:\n${err.stack}`);
    
    // 如果响应头尚未发送，则发送错误响应
    if (!res.headersSent) {
        res.status(500).json({ 
            error: '服务器内部错误',
            timestamp: new Date().toISOString(),
            requestId: Date.now() + '-' + Math.random().toString(36).substr(2, 9)
        });
    } else {
        // 如果响应头已发送，则结束响应
        res.end();
    }
});

// 保存服务器实例以便后续关闭
let server;

// 启动服务器
const PORT = process.env.PORT || config.server.port;
server = app.listen(PORT, () => {
    const startTime = new Date().toISOString();
    const os = require('os');
    const networkInterfaces = os.networkInterfaces();
    let localIPs = [];
    
    // 获取本地IP地址
    Object.keys(networkInterfaces).forEach(interfaceName => {
        networkInterfaces[interfaceName].forEach(interface => {
            if (!interface.internal && interface.family === 'IPv4') {
                localIPs.push(interface.address);
            }
        });
    });

    console.log(`${startTime} =====================================`);
    console.log(`${startTime}      短视频服务器启动成功！`);
    console.log(`${startTime} =====================================`);
    console.log(`${startTime} 访问地址: http://127.0.0.1:${PORT}`);
    localIPs.forEach(ip => {
        console.log(`${startTime} 局域网访问: http://${ip}:${PORT}`);
    });
    console.log(`${startTime} 视频目录: ${serverConfig.videosDirectory}`);
    console.log(`${startTime} 支持格式: ${serverConfig.supportedExtensions.join(', ')}`);
    console.log(`${startTime} 索引文件: ${serverConfig.indexFilePath}`);
    console.log(`${startTime} 索引缓存: ${(serverConfig.maxIndexAge / 1000 / 60 / 60).toFixed(1)}小时`);
    console.log(`${startTime} Node版本: ${process.version}`);
    console.log(`${startTime} 系统平台: ${process.platform} (${os.arch()})`);
    console.log(`${startTime} =====================================`);

    // 启动时生成索引
    getVideoIndex().then(() => {
        console.log(`${new Date().toISOString()} 服务器初始化完成`);
    }).catch((error) => {
        console.error(`${new Date().toISOString()} 服务器初始化失败:`, error.message);
    });
});

// 优雅关闭服务器
process.on('SIGINT', () => {
    console.log(`${new Date().toISOString()} 接收到 SIGINT 信号 (${process.pid})，正在关闭服务器...`);
    shutdown('SIGINT');
});

process.on('SIGTERM', () => {
    console.log(`${new Date().toISOString()} 接收到 SIGTERM 信号 (${process.pid})，正在关闭服务器...`);
    shutdown('SIGTERM');
});

function shutdown(signal) {
    console.log(`${new Date().toISOString()} 开始执行服务器关闭流程 (${signal})...`);
    
    // 关闭服务器，阻止新连接
    server.close(() => {
        console.log(`${new Date().toISOString()} HTTP服务器已关闭`);
    });
    
    // 统计信息
    const uptime = process.uptime();
    console.log(`${new Date().toISOString()} 服务器运行时间: ${Math.floor(uptime / 60)}分${Math.floor(uptime % 60)}秒`);
    
    // 给服务器5秒时间来处理现有连接
    const forceCloseTimeout = setTimeout(() => {
        console.log(`${new Date().toISOString()} 强制关闭服务器 (超时)`);
        process.exit(0);
    }, 5000);
    
    // 如果服务器正常关闭，清除超时定时器
    server.on('close', () => {
        clearTimeout(forceCloseTimeout);
        console.log(`${new Date().toISOString()} 服务器已正常关闭`);
        process.exit(0);
    });
}

module.exports = app;